﻿using System;
using jade.core;
using jade.core.behaviours;
using jade.lang.acl;
using jade.domain.FIPAAgentManagement;
using jade.content.lang;
using log4net;
using jade.content;
using jade.content.lang.leap;
using Action = jade.content.onto.basic.Action;
using jade.domain.JADEAgentManagement;
using jade.content.onto.basic;
using GatewayUtil.agents.ontology;
using DynamicWSInvoker;
using jade.util.leap;
using jade.content.onto;



namespace GatewayUtil.agents
{
    /// <summary>
    /// 
    /// </summary>
    public class WSInvokerAgent : Agent
    {
        private static readonly ILog log = LogManager.GetLogger(typeof(WSInvokerAgent));
        private Ontology onto = DynamicWSOntology.getInstance();
        public static Codec codec = new LEAPCodec();
        public override void setup()
        {
            log.Info("Starting agent with name "+this.getAID().getLocalName());


            getContentManager().registerLanguage(codec);
            getContentManager().registerOntology(FIPAManagementOntology.getInstance());
            getContentManager().registerOntology(JADEManagementOntology.getInstance());
            getContentManager().registerOntology(onto);

            this.getContentManager().setValidationMode(false);

            this.setEnabledO2ACommunication(true, 30);

            addBehaviour(new WSInvokeBehaviour(this));
            debug("Gateway agent is set up!");
        }

        public override void takeDown()
        {
            base.takeDown();
            log.Info("Agent "+this.getAID().getLocalName()+" taken down!");
        }

        private void debug(string p)
        {
            log.Debug(this.getLocalName() + ": " + p);

        }
        private void error(string p)
        {
            log.Error(this.getLocalName() + ": " + p);
        }

        private void error(Exception e)
        {
            log.Error(e);
        }


        class WSInvokeBehaviour : SimpleBehaviour
        {
            
            bool finished = false;
            private MessageTemplate template = MessageTemplate.MatchOntology(DynamicWSOntology.getInstance().getName());
            public WSInvokeBehaviour(Agent a)
                : base(a)
            {
                ((WSInvokerAgent)this.myAgent).debug("WSInvokeBehaviour started!");
            }

            public override void action()
            {
                try
                {
                    ((WSInvokerAgent)this.myAgent).debug("WSInvokeBehaviour is ready");
                    ACLMessage msg = this.myAgent.receive(template);
                    if (msg != null)
                    {
                        this.myAgent.getContentManager().setValidationMode(false);
                        Action action = (Action)this.myAgent.getContentManager().extractContent(msg);
                        AgentAction agentAction = (AgentAction)action.getAction();
                        WSResponse wsResponse = null;

                        if (agentAction is WSRequest)
                        {
                            wsResponse = performWSRequest((WSRequest)agentAction);
                        }
                        else
                        {
                            // error state
                            log.Error("AgentAction is not valid, its type is " + agentAction.GetType().FullName);
                        }
                        Result result = new Result(action, wsResponse);
                        ContentElement content = result;

                        ACLMessage reply = msg.createReply();
                        reply.setPerformative(ACLMessage.INFORM);

                        this.myAgent.getContentManager().fillContent(reply, content);
                        reply.addUserDefinedParameter(ACLMessage.IGNORE_FAILURE, "true");

                        ((WSInvokerAgent)this.myAgent).debug("Sending response");
                        this.myAgent.send(reply);
                        ((WSInvokerAgent)this.myAgent).debug("The message was successfully sent back");

                    }
                    else block();
                }
                catch(Exception e)
                {
                    log.Error("Exception in WSInvokerAgent",e);
                    throw e;
                }
            }

            private WSResponse performWSRequest(WSRequest wsRequest)
            {
                Iterator iter = ((ArrayList)wsRequest.getAllArguments().next()).iterator();
                ArrayList args = new ArrayList();
                while(iter.hasNext())
                {
                    args.add(iter.next());
                }
                WSInvoker invoker = new WSInvoker(wsRequest.getServiceURL(), wsRequest.getServiceName(), wsRequest.getMethodName(), args.toArray());
                Object result = invoker.invoke();
                WSResponse wsResponse = new WSResponse();
                wsResponse.setResponseObject(result);
                return wsResponse;
            }


            public override bool done()
            {
                return finished;
            }
        }




        }
    }



